package goquery
import (
"bytes"
"regexp"
"strings"
"golang.org/x/net/html"
)
var rxClassTrim = regexp .MustCompile ("[\t\r\n]" )
func (s *Selection ) Attr (attrName string ) (val string , exists bool ) {
if len (s .Nodes ) == 0 {
return
}
return getAttributeValue (attrName , s .Nodes [0 ])
}
func (s *Selection ) AttrOr (attrName , defaultValue string ) string {
if len (s .Nodes ) == 0 {
return defaultValue
}
val , exists := getAttributeValue (attrName , s .Nodes [0 ])
if !exists {
return defaultValue
}
return val
}
func (s *Selection ) RemoveAttr (attrName string ) *Selection {
for _ , n := range s .Nodes {
removeAttr (n , attrName )
}
return s
}
func (s *Selection ) SetAttr (attrName , val string ) *Selection {
for _ , n := range s .Nodes {
attr := getAttributePtr (attrName , n )
if attr == nil {
n .Attr = append (n .Attr , html .Attribute {Key : attrName , Val : val })
} else {
attr .Val = val
}
}
return s
}
func (s *Selection ) Text () string {
var buf bytes .Buffer
var f func (*html .Node )
f = func (n *html .Node ) {
if n .Type == html .TextNode {
buf .WriteString (n .Data )
}
if n .FirstChild != nil {
for c := n .FirstChild ; c != nil ; c = c .NextSibling {
f (c )
}
}
}
for _ , n := range s .Nodes {
f (n )
}
return buf .String ()
}
func (s *Selection ) Size () int {
return s .Length ()
}
func (s *Selection ) Length () int {
return len (s .Nodes )
}
func (s *Selection ) Html () (ret string , e error ) {
var buf bytes .Buffer
if len (s .Nodes ) > 0 {
for c := s .Nodes [0 ].FirstChild ; c != nil ; c = c .NextSibling {
e = html .Render (&buf , c )
if e != nil {
return
}
}
ret = buf .String ()
}
return
}
func (s *Selection ) AddClass (class ...string ) *Selection {
classStr := strings .TrimSpace (strings .Join (class , " " ))
if classStr == "" {
return s
}
tcls := getClassesSlice (classStr )
for _ , n := range s .Nodes {
curClasses , attr := getClassesAndAttr (n , true )
for _ , newClass := range tcls {
if !strings .Contains (curClasses , " " +newClass +" " ) {
curClasses += newClass + " "
}
}
setClasses (n , attr , curClasses )
}
return s
}
func (s *Selection ) HasClass (class string ) bool {
class = " " + class + " "
for _ , n := range s .Nodes {
classes , _ := getClassesAndAttr (n , false )
if strings .Contains (classes , class ) {
return true
}
}
return false
}
func (s *Selection ) RemoveClass (class ...string ) *Selection {
var rclasses []string
classStr := strings .TrimSpace (strings .Join (class , " " ))
remove := classStr == ""
if !remove {
rclasses = getClassesSlice (classStr )
}
for _ , n := range s .Nodes {
if remove {
removeAttr (n , "class" )
} else {
classes , attr := getClassesAndAttr (n , true )
for _ , rcl := range rclasses {
classes = strings .Replace (classes , " " +rcl +" " , " " , -1 )
}
setClasses (n , attr , classes )
}
}
return s
}
func (s *Selection ) ToggleClass (class ...string ) *Selection {
classStr := strings .TrimSpace (strings .Join (class , " " ))
if classStr == "" {
return s
}
tcls := getClassesSlice (classStr )
for _ , n := range s .Nodes {
classes , attr := getClassesAndAttr (n , true )
for _ , tcl := range tcls {
if strings .Contains (classes , " " +tcl +" " ) {
classes = strings .Replace (classes , " " +tcl +" " , " " , -1 )
} else {
classes += tcl + " "
}
}
setClasses (n , attr , classes )
}
return s
}
func getAttributePtr(attrName string , n *html .Node ) *html .Attribute {
if n == nil {
return nil
}
for i , a := range n .Attr {
if a .Key == attrName {
return &n .Attr [i ]
}
}
return nil
}
func getAttributeValue(attrName string , n *html .Node ) (val string , exists bool ) {
if a := getAttributePtr (attrName , n ); a != nil {
val = a .Val
exists = true
}
return
}
func getClassesAndAttr(n *html .Node , create bool ) (classes string , attr *html .Attribute ) {
if n .Type == html .ElementNode {
attr = getAttributePtr ("class" , n )
if attr == nil && create {
n .Attr = append (n .Attr , html .Attribute {
Key : "class" ,
Val : "" ,
})
attr = &n .Attr [len (n .Attr )-1 ]
}
}
if attr == nil {
classes = " "
} else {
classes = rxClassTrim .ReplaceAllString (" " +attr .Val +" " , " " )
}
return
}
func getClassesSlice(classes string ) []string {
return strings .Split (rxClassTrim .ReplaceAllString (" " +classes +" " , " " ), " " )
}
func removeAttr(n *html .Node , attrName string ) {
for i , a := range n .Attr {
if a .Key == attrName {
n .Attr [i ], n .Attr [len (n .Attr )-1 ], n .Attr =
n .Attr [len (n .Attr )-1 ], html .Attribute {}, n .Attr [:len (n .Attr )-1 ]
return
}
}
}
func setClasses(n *html .Node , attr *html .Attribute , classes string ) {
classes = strings .TrimSpace (classes )
if classes == "" {
removeAttr (n , "class" )
return
}
attr .Val = classes
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .